import { reactive, ref, toRefs, onBeforeUnmount } from 'vue';
import { useQuasar } from '@teld/q-components';
import _ from 'lodash';

/**
 * @summary 滚动加载模式下，滚动时提示【当前第n条，共n条结果】
 * @descripttion 列表展示出来必然是第一条，这个无需提示，
 * 只有当滚动后用户就不清楚当前是第几条了，这时候才需要提示
 * @remarks 关于提示当前的index，判断处理是分场景的
 * 1. 当循环项高度大，一页无法完全展示开时，根据退出可视区域的项目进行计算，其前后项作为当前
 * 2. 当循环项高度小，一页可以完全展示开时，哪个完全展示开，哪个作为当前
 *    2.1 向上滚动根向下滚动时，获得的循环项是不同的
 * 3. 这种判断不能同时设置，只能销毁一个，重新设
 * 4. 基于每个循环项的高度是相同的，所以加载出数据后会根据循环项高度，对监测进行重新设置
 */
export default (listRef, listTotal, props) => {
  let qNotify = null;
  const $q = useQuasar();
  const observer = ref();
  const scrollCounting = ref(0);
  const scrollCountingVisible = ref(false);
  const intersectionConfig = reactive({
    rootMargin: '0px',
    threshold: 1,
  });
  let timer = null;

  const delayToHideNotification = () => {
    timer && clearTimeout(timer);
    timer = setTimeout(() => {
      scrollCountingVisible.value = false;
    }, props.hideScrollNotificationDelay || 1000);
  };

  const handleCase1 = entries => {
    const itemsIntersecting = entries.filter(n => n.isIntersecting);
    const item = itemsIntersecting.shift();
    const index = item && item.target.dataset.rowIndex; // undefined | '0' | '1'..
    // 非循环元素
    if (!index) return;

    const currentIndex = parseInt(index) + 1;
    console.log(`滚动对象${parseInt(index) + 1}  --  提示 ${currentIndex}`);
    scrollCounting.value = currentIndex;
    scrollCountingVisible.value = true;
    delayToHideNotification();

    // if (index) {
    //   // 先关掉之前的
    //   qNotify && qNotify();
    //   qNotify = $q.notify({
    //     message: _.template($q.lang.tRepeat.currentInTotal)({
    //       current: parseInt(index) + 1,
    //       totalCount: listTotal.value,
    //     }),
    //     position: 'center',
    //     color: 'grey-9',
    //     icon: 'none', // 虽然不显示icon但是仍有空位置，需要手动调样式
    //     attrs: {
    //       // 为通知的 DOM 本身设置属性:
    //       'notification-toast': true, // 这是为了做精准选择器调样式用的
    //     },
    //     timeout: 1500,
    //   });
    // }
    // }
  };
  const handleCase2 = entries => {
    const targetEntry = entries[0];
    const {
      isIntersecting,
      boundingClientRect,
      intersectionRect,
      rootBounds,
      target,
    } = targetEntry;
    // let currentIndex = 0;

    console.log(targetEntry);
    if (isIntersecting) {
      // TODO 将来如果需要考虑一页内展示开多个元素，就需要分别处理
      return;
    }

    const index = target.dataset.rowIndex; // undefined | '0' | '1'..
    // 非循环元素
    if (!index) return;

    let direction = 1;

    // 没有完全消失时，在 rootMargin 范围内
    if (intersectionRect.height > 0) {
      // 消失于底部
      if (
        boundingClientRect.bottom - intersectionRect.bottom >
        intersectionRect.top - boundingClientRect.top
      ) {
        direction = -1;
      }
    } else {
      // 完全消失于可视区域
      if (boundingClientRect.top > rootBounds.bottom) {
        // 消失于底部
        direction = -1;
      }
    }

    const currentIndex = parseInt(index) + 1 + direction;
    console.log(`滚动对象${parseInt(index) + 1}  --  提示 ${currentIndex}`);
    scrollCounting.value = currentIndex;
    scrollCountingVisible.value = true;
    delayToHideNotification();

    // if (currentIndex > 0) {
    //   // 先关掉之前的
    //   qNotify && qNotify();
    //   qNotify = $q.notify({
    //     message: _.template($q.lang.tRepeat.currentInTotal)({
    //       current: currentIndex,
    //       totalCount: listTotal.value,
    //     }),
    //     position: 'center',
    //     color: 'grey-9',
    //     icon: 'none', // 虽然不显示icon但是仍有空位置，需要手动调样式
    //     attrs: {
    //       // 为通知的 DOM 本身设置属性:
    //       'notification-toast': true, // 这是为了做精准选择器调样式用的
    //     },
    //     timeout: 99991000,
    //   });
    // }
  };

  /**
   * 循环组件-滚动时提示信息的实现逻辑
   * 首先，假定，循环元素每一个是同样大的
   * 然后，存在两种情况，它们的处理逻辑是截然不同的
   * - Case1 容器内显示多于一个元素
   * - Case2 循环元素非常大，容器内显示不开一个元素
   * 最后，计算当前的index：元素滚动消失时，它相邻的前后元素即为当前元素
   */
  const getObserveCallback = showingMulti => {
    return showingMulti ? handleCase1 : handleCase2;
  };

  const stopObserve = () => {
    if (observer.value) {
      observer.value.disconnect();
      observer.value = null;
    }
  };

  /**
   * 设置 IntersectionObserver 监听器
   *
   * @remarks
   * 如果已经存在 observer 则先断开连接并清空，然后重新创建一个新的 IntersectionObserver 监听器。
   */
  const setupIntersectionObserver = (observeCallback = handleCase1) => {
    stopObserve();
    scrollCounting.value = 0;
    observer.value = new IntersectionObserver(observeCallback, {
      root: listRef.value.$el || listRef.value,
      rootMargin: intersectionConfig.rootMargin,
      threshold: intersectionConfig.threshold,
    });
  };

  /**
   * 数据加载后根据循环项高度，重新设置观察器
   * @param {number} itemHeight
   */
  const resetObserver = itemHeight => {
    const containerHeight = listRef.value.$el.clientHeight;

    const showingMulti = itemHeight < containerHeight;
    intersectionConfig.rootMargin = showingMulti
      ? '0px'
      : '-100px 0px -100px 0px';
    intersectionConfig.threshold = showingMulti ? 1 : 0;
    setupIntersectionObserver(getObserveCallback(showingMulti));
    console.log(
      `是否一页显示不开：${!showingMulti} - ${showingMulti ? '显示完整的才算' : '消失时计算'}`,
    );
  };

  /**
   * 在滚动加载完成后开始观察滚动项
   *
   * @returns 无返回值
   */
  const beginObserveAfterScrollLoaded = elList => {
    if (!observer.value) return;

    [].forEach.call(elList, item => {
      observer.value.observe(item);
    });
  };

  onBeforeUnmount(() => {
    stopObserve();
  });

  return {
    observer,
    scrollCounting,
    scrollCountingVisible,
    setupIntersectionObserver,
    resetObserver,
    beginObserveAfterScrollLoaded,
    stopObserve,
  };
};
